package org.iabako.shared.tools;

import com.google.gwt.i18n.client.LocaleInfo;
import com.google.gwt.i18n.client.NumberFormat;
import com.google.gwt.i18n.shared.DateTimeFormat;
import com.google.gwt.i18n.shared.DefaultDateTimeFormatInfo;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.EventListener;
import com.google.gwt.user.client.ui.IsWidget;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.datepicker.client.CalendarUtil;

import java.math.BigInteger;
import java.security.MessageDigest;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * TODO javadoc
 * Date: 24/11/13
 * Time: 18:22
 */
public class GenericTools implements DateTools {

    public static boolean isEmpty(Object... objects) {
        for (Object o : objects) {
            if (isEmpty(o)) {
                return true;
            }
        }
        return false;
    }

    public static boolean isEmpty(Object o) {
        if (o == null) {
            return true;
        }
        if (o instanceof String) {
            return ((String) o).trim().isEmpty();
        }
        return (o instanceof Collection && ((Collection) o).isEmpty())
                || (o instanceof Map && ((Map) o).isEmpty());
    }

    public static boolean isEmptyOrZero(Object o) {
        if (o == null) {
            return true;
        }
        if (o instanceof String) {
            return ((String) o).trim().isEmpty() || ((String) o).trim().equals("0");
        } else if (o instanceof Double) {
            return ((Double) o) == 0d;
        } else if (o instanceof Integer) {
            return ((Integer) o) == 0;
        } else if (o instanceof Long) {
            return ((Long) o) == 0l;
        }
        return false;
    }

    public static IsWidget getWidget(com.google.gwt.user.client.Element element) {
        if (element == null) {
            return null;
        }
        EventListener listener = DOM
                .getEventListener((com.google.gwt.user.client.Element) element);
        // No listener attached to the element, so no widget exist for this
        // element
        if (listener == null) {
            return null;
        }
        if (listener instanceof Widget) {
            // GWT uses the widget as event listener
            return (Widget) listener;
        }
        return null;
    }

    public static String getYear(Date date) {
        if (GenericTools.isEmpty(date)) {
            return "";
        }
        DefaultDateTimeFormatInfo info = new DefaultDateTimeFormatInfo();
        //Hack for use in server AND client side
        DateTimeFormat dtf = new DateTimeFormat("yyyy", info) {
        };
        return dtf.format(date);
    }

    public static String formatSmallDate(Date date) {
        if (GenericTools.isEmpty(date)) {
            return "";
        }
        DefaultDateTimeFormatInfo info = new DefaultDateTimeFormatInfo();
        //Hack for use in server AND client side
        DateTimeFormat dtf = new DateTimeFormat("dd/MM", info) {
        };
        return dtf.format(date);
    }

    public static String formatDate(Date date) {
        if (GenericTools.isEmpty(date)) {
            return "";
        }
        DefaultDateTimeFormatInfo info = new DefaultDateTimeFormatInfo();
        //Hack for use in server AND client side
        DateTimeFormat dtf = new DateTimeFormat("dd/MM/yyyy", info) {
        };
        return dtf.format(date);
    }

    public static String formatDateSql(Date date) {
        if (GenericTools.isEmpty(date)) {
            return "";
        }
        DefaultDateTimeFormatInfo info = new DefaultDateTimeFormatInfo();
        //Hack for use in server AND client side
        DateTimeFormat dtf = new DateTimeFormat("yyyy-MM-dd hh:mm:ss", info) {
        };
        return dtf.format(date);
    }

    public static String formatTime(Date date) {
        if (GenericTools.isEmpty(date)) {
            return "";
        }
        DefaultDateTimeFormatInfo info = new DefaultDateTimeFormatInfo();
        //Hack for use in server AND client side
        DateTimeFormat dtf = new DateTimeFormat("dd/MM/yyyy HH:mm", info) {
        };
        return dtf.format(date);
    }

    public static String formatDateyyyyMMdd(Date date) {
        if (GenericTools.isEmpty(date)) {
            return "";
        }
        DefaultDateTimeFormatInfo info = new DefaultDateTimeFormatInfo();
        //Hack for use in server AND client side
        DateTimeFormat dtf = new DateTimeFormat("yyyy-MM-dd", info) {
        };
        return dtf.format(date);
    }

    public static Date getDate(String ddMMyyyy) {
        DefaultDateTimeFormatInfo info = new DefaultDateTimeFormatInfo();
        //Hack for use in server AND client side
        DateTimeFormat dtf = new DateTimeFormat("dd/MM/yyyy", info) {
        };
        try {
            return dtf.parseStrict(ddMMyyyy);
        } catch (Exception e) {
            return null;
        }
    }

    public static Date getDateWithoutTime(Date date) {
        return getDate(GenericTools.formatDate(date));
    }

    public static Date getDateDay() {
        return getDate(formatDate(new Date()));
    }

    public static String formatDateToString(Date date) {
        if (GenericTools.isEmpty(date)) {
            return "";
        }
        DefaultDateTimeFormatInfo info = new DefaultDateTimeFormatInfo();
        //Hack for use in server AND client side
        DateTimeFormat dtf = new DateTimeFormat("yyyyMMddHHmmss", info) {
        };
        return dtf.format(date);
    }

    public static Date getDateFromString(String yyyyMMddHHmmss) {
        DefaultDateTimeFormatInfo info = new DefaultDateTimeFormatInfo();
        //Hack for use in server AND client side
        DateTimeFormat dtf = new DateTimeFormat("yyyyMMddHHmmss", info) {
        };
        try {
            return dtf.parseStrict(yyyyMMddHHmmss);
        } catch (Exception e) {
            return null;
        }
    }

    public Date addDaysToDate(Date date, int days) {
        CalendarUtil.addDaysToDate(date, days);
        return date;
    }

    public Date addMonthsToDate(Date date, int months) {
        int dateBefore = date.getDate();
        CalendarUtil.addMonthsToDate(date, months);
        int dateAfter = date.getDate();

        if (dateBefore != dateAfter) {
            //initial Date was in the last days of a month (ex. 31-Jan) and this produced an unexpected offset
            //That must be fixed by the following hack :
            date.setDate(1);
            date = addDaysToDate(date, -1);
        }

        return date;
    }

    public static String formatAmount(String value) {
        if (isEmpty(value)) {
            return value;
        }
        try {
            String amount = value.replace(" ", "").replace(",", ".");
            String groupingSeparator = LocaleInfo.getCurrentLocale().getNumberConstants().groupingSeparator();
            return NumberFormat.getFormat("#,##0.00").format(Double.parseDouble(amount)).replace(groupingSeparator, " ");
        } catch (NumberFormatException e) {
            return value;
        }
    }

    public static Double parseAmount(String value) {
        if (GenericTools.isEmpty(value)) {
            return null;
        }
        try {
            String amount = value.replace(" ", "").replace(",", ".");
            return Double.parseDouble(amount);
        } catch (NumberFormatException e) {
            return null;
        } catch (NullPointerException e) {
            return null;
        }
    }

    public static Date getDateWithoutTime() {
        Date date = new Date();
        DefaultDateTimeFormatInfo info = new DefaultDateTimeFormatInfo();
        //Hack for use in server AND client side
        DateTimeFormat dtf = new DateTimeFormat("yyyy", info) {
        };
        String year = dtf.format(date);
        dtf = new DateTimeFormat("M", info) {
        };
        String month = dtf.format(date);
        dtf = new DateTimeFormat("d", info) {
        };
        String day = dtf.format(date);
        dtf = new DateTimeFormat("d-M-yyyy", info) {
        };
        return dtf.parse(day + "-" + month + "-" + year);
    }

    public static String getMd5(String text) {
        if (isEmpty(text)) {
            return null;
        }
        MessageDigest messageDigest = null;
        try {
            messageDigest = MessageDigest.getInstance("MD5");

            messageDigest.update(text.getBytes(), 0, text.length());
            String hashedText = new BigInteger(1, messageDigest.digest()).toString(16);
            if (hashedText.length() < 32) {
                hashedText = "0" + hashedText;
            }
            return hashedText;
        } catch (Exception e) {
            return null;
        }
    }

    public static String getHtmlStyleForEnterpriseLogo(int width, int height) {
        int maxHeight = 100;
        int maxWidth = 330;
        int newHeight = height;
        int newWidth = width;
        int heightDiff = height - maxHeight;
        int widthDiff = width - maxWidth;
        double heightResizeProp = heightDiff * 1d / height;
        double widthResizeProp = widthDiff * 1d / width;
        if (height > maxHeight && width > maxWidth) {
            newHeight = heightResizeProp > widthResizeProp ? maxHeight : new Double(height - (height * widthResizeProp)).intValue();
            newWidth = heightResizeProp > widthResizeProp ? new Double(width - (width * heightResizeProp)).intValue() : maxWidth;
        } else if (height > maxHeight) {
            newHeight = maxHeight;
            newWidth = new Double(width - (width * heightResizeProp)).intValue();
        } else if (width > maxWidth) {
            newHeight = new Double(height - (height * widthResizeProp)).intValue();
            newWidth = maxWidth;
        }

        return " width:" + newWidth + "px; height:" + newHeight + "px;";
    }

    public static String listAsString(List list) {
        if (list == null || list.isEmpty()) {
            return null;
        }
        String listAsString = "";
        for (Object o : list) {
            if (isEmpty(o)) {
                continue;
            }
            listAsString += o + ", ";
        }
        return listAsString.contains(", ") ? listAsString.substring(0, listAsString.lastIndexOf(", ")) : null;
    }
}
